(function(window) {

	/**
	 * Use this as a configurable browser console logger.<br/>
	 * 
	 * Example<br/>
	 * <br/>
	 * Logger.debug("This is a test debug");<br/>
	 * Logger.warn("This is a test warning");<br/>
	 * <br/>
	 * setting log level to debug: <i>Logger.level(Logger.DEBUG);</i> will cause all of these 
	 * messages to be printed to console. Where as warn: <i>Logger.level(Logger.WARN);</i> will cause
	 * only the warning to be printed and error: <i>Logger.level(Logger.ERROR);</i> (or NONE) will
	 * remove all logging messages from the browser.
	 * 
	 * @namespace Logger
	 */
	Types.exportSymbol("Logger", Logger());
	
	function Logger() {
		
		/**
		 * @type Logger#
		 */
		var that = {};

		that.DEBUG = 0;
		that.INFO = 1;
		that.WARN = 2;
		that.ERROR = 3;
		that.NONE = 10;

		var ERROR_TEST = false;
		var ERROR = false;
		var WARN = false;
		var INFO = false;
		var DEBUG = false;
			
		/**
		 * @memberOf Logger
		 * @name Logger.error
		 */
		that.error = function(msg) {
		};

		/**
		 * @memberOf Logger
		 * @name Logger.warn
		 */
		that.warn = function(msg) {
		};

		/**
		 * @memberOf Logger
		 * @name Logger.debug
		 */
		that.debug = function(msg) {
		};

		/**
		 * @memberOf Logger
		 * @name Logger.info
		 */
		that.info = function(msg) {
		};

		/** @expose */
		that.logsOff = function() {
			that.error = function(msg) {
			};
			that.warn = function(msg) {
			};
			that.debug = function(msg) {
			};
			that.info = function(msg) {
			};
		};
		
		/**
		 * @memberOf Logger
		 * @name Logger.logsOff
		 */
		that.logsOff();

		/**
		 * @memberOf Logger
		 * @name level
		 */
		that.level = function level(mode) {

			if ( typeof mode == "undefined") {
				mode = that.DEBUG;
			}

			ERROR_TEST = false;
			ERROR = false;
			WARN = false;
			INFO = false;
			DEBUG = false;

			that.logsOff();

			if (mode == that.DEBUG) {
				ERROR = true;
				WARN = true;
				INFO = true;
				DEBUG = true;
			} else if (mode == that.INFO) {
				ERROR = true;
				WARN = true;
				INFO = true;
			} else if (mode == that.WARN) {
				ERROR = true;
				WARN = true;
			} else if (mode == that.ERROR) {
				ERROR = true;
			}

			that.setupLogs();
		};

		that.setupLogs = function() {

			var consoleLogBindSupport = false;
			var consoleLogSupport = false;
			if (window.console) {
				if (window.console.log) {
					consoleLogSupport = true;
					if (window.console.log.bind) {
						consoleLogBindSupport = true;
					}
				}
			}
			var consoleErrorBindSupport = false;
			var consoleErrorSupport = false;
			if (window.console) {
				if (window.console.error) {
					consoleErrorSupport = true;
					if (window.console.error.bind) {
						consoleErrorBindSupport = true;
					}
				}
			}


			if (ERROR_TEST) {
				if ( typeof console.error == 'function') {
					//
					that.error = function(msg) {
						var caller = arguments.callee.caller;
						var myArguments = arguments;
						myArguments.callee = caller.caller.caller.caller;
						console.trace.apply(console, myArguments);
						var getStackTrace = function() {
							var obj = {};
							Error.captureStackTrace(obj, getStackTrace);
							return obj.stack;
						};

						var trace = getStackTrace();
						console.log("bar:" + trace[2]);
					};
				} else {
					msg = "[ERROR] " + msg;
					that.error = function(msg) {

						setTimeout(function() {
							throw new Error(msg);
						}, 0);
					};
				}
			}
			if (ERROR) {
				if (consoleErrorBindSupport) {
					that.error = console.error.bind(console);
				} else if(consoleErrorSupport) {
					that.error = function(message) {
						console.error(message);
					}
				} else {
					that.error = function(msg) {
						msg = "[ERROR] " + msg;
						setTimeout(function() {
							throw new Error(msg);
						}, 0);
					};
				}
			}

			if (WARN) {
				if (consoleErrorBindSupport) {
					that.warn = console.error.bind(console);
				} else if(consoleErrorSupport) {
					that.warn = function(message) {
						console.error(message);
					}
				} else {
					that.warn = function(msg) {
						msg = "[WARN] " + msg;
						setTimeout(function() {
							throw new Error(msg);
						}, 0);
					};
				}
			}

			if (INFO) {
				if(consoleLogBindSupport) {
					that.info = console.log.bind(console);
				} else if(consoleLogSupport) {
					that.info = function(message) {
						console.log(message);
					}
				}
			}
			if (DEBUG) {
				if(consoleLogBindSupport) {
					that.debug = console.log.bind(console);
				} else if(consoleLogSupport) {
					that.debug = function(message) {
						console.log(message);
					}
				}
			}
		};
		return that;
	};

	/**
	 * @memberOf Logger
	 * @name Logger.initDevMode
	 */
	initDevMode = function() {
		Logger.initDevMode();
		Assert.initDevMode();
	};

	/**
	 * Get a random string
	 * @param length
	 * @expose
	 */
	function randomString(length) {
		var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
		var randomstring = '';
		for (var i = 0; i < length; i++) {
			var rnum = Math.floor(Math.random() * chars.length);
			randomstring += chars.substring(rnum, rnum + 1);
		}
		return randomstring;
	}
		
})(this);
